package indi.defoliation.unknownrpg.api;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;

import com.google.common.collect.Maps;

import indi.defoliation.unknownrpg.api.attribute.Attribute;
import indi.defoliation.unknownrpg.api.attribute.SingleValueAttribute;
import team.unstudio.udpl.config.SerializationHelper;
import team.unstudio.udpl.nms.NmsHelper;
import team.unstudio.udpl.nms.inventory.NmsItemStack;
import team.unstudio.udpl.nms.nbt.NBTBase;
import team.unstudio.udpl.nms.nbt.NBTTagCompound;

public class RPGItemFactory {

	public static final String NBT_PREFIX = "UnknownRPG_";

	public static RPGItem getRPGItem(ItemStack item) {
		return getRPGItem(item,new UnknownRPGItem());
	}
	
	public static RPGItem getRPGItem(ItemStack item,RPGItem rpgItem) {
		NmsItemStack nmsItem = NmsHelper.createNmsItemStack(item.clone());
		if(!nmsItem.hasTag())return rpgItem;
		NBTTagCompound  nbt  =nmsItem.getTag();
		for(Attribute att : RPGItemManager.getRegisteredAttributes()) {
			Map<String,Object> map = Maps.newLinkedHashMap();
			for(String key : nbt.keySet()) {
				if(!key.startsWith(NBT_PREFIX+att.getKeyName()))continue;
				NBTBase base = nbt.get(NBT_PREFIX+att.getKeyName()+key);
				if(base ==null)continue;
				map.put(key.substring(NBT_PREFIX.length()+1), base.toString());
			}
			if(map.isEmpty())continue;
			rpgItem.addAttribute(SerializationHelper.deserialize(att.clone(), map));
		}
		//这玩意，应该要炸。
		return rpgItem;
	}


	/**
	 * 以yaml的方式加载文件.
	 * <br>
	 * 
	 * @param itemFile 需要转换的文件对象
	 * @return 返回已经加载完毕的RPGItem
	 * @throws FileNotFoundException
	 * @throws IOException
	 * @throws InvalidConfigurationException
	 */
	public static RPGItem getRPGItem(YamlConfiguration itemFile) throws FileNotFoundException, IOException, InvalidConfigurationException {
		return getRPGItem(itemFile,new UnknownRPGItem());
	}
	
	public static RPGItem getRPGItem(YamlConfiguration itemFile,RPGItem item) throws FileNotFoundException, IOException, InvalidConfigurationException {
		for(Attribute att : RPGItemManager.getRegisteredAttributes()) {
			Map<String,Object> map = Maps.newLinkedHashMap();
			Attribute att1 = att.clone();
			for(String key : itemFile.getKeys(true)) {
				if(key.equals(att.getKeyName())&&att instanceof SingleValueAttribute) {
					Object o = itemFile.get(att.getKeyName());
					if(o==null)continue;
					map.put(att.getKeyName(), o);
				}else
					if(key.startsWith(att.getKeyName())) {
						map.put(key.substring(att.getKeyName().length()+1), itemFile.get(key));
					}
			}
			if(!map.isEmpty())
				att1.deserialize(map);
			item.addAttribute(att1);
		}
		return item;
	}

	private static class UnknownRPGItem implements RPGItem {

		private Set<Attribute> attributeSet = new HashSet<>();

		public void addAttribute(Attribute att) {
			this.attributeSet.add(att);
		}
		public Set<Attribute> getAttributes() {
			return this.attributeSet;
		}
		
		public Attribute getAttribute(String keyName) {
			for(Attribute att:attributeSet) {
				if(att.getKeyName().equals("keyName"))
					return att;
			}
			return null;
		}

		public void removeAttribute(Attribute att) {
			this.attributeSet.remove(att);
		}
		public ItemStack setInItemStack(ItemStack item) {

			NmsItemStack nbtItem = NmsHelper.createNmsItemStack(item.clone());

			NBTTagCompound nbt = nbtItem.getTag();

			for(String attNbt : nbt.keySet())
				if(attNbt.startsWith(NBT_PREFIX))
					nbt.remove(attNbt);

			for(Attribute att : this.getAttributes()) {

				Map<String,Object> map =SerializationHelper.serialize(att);


				for(String key : map.keySet()) {
					nbt.setString(NBT_PREFIX+key,map.get(key).toString());

				}
			}

			nbtItem.setTag(nbt);
			return nbtItem.getBukkitItemStack();
		}
		@Override
		public boolean hasAttribute(String att) {
			for(Attribute att1 : attributeSet) {
				if(att1.getKeyName().equals(att))
					return true;
			}
			return false;
		}
	}
}
